/***************************************************************************
 *   Copyleft 2006-2007 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#include "./Torus.h"
#include "../../Macros/Macros.h"
#include "../Graphics/Color.h"
#include <math.h>

/**************************************************************
* Constructors                                                *
***************************************************************/
Torus::Torus(cFloat fIRadius, cFloat fERadius, cInt iU, cInt iV): Object3D() {
	mColor = Color::ToWinColor(Color(0.0f, 0.23f, 1.0f));
	Update(fIRadius, fERadius, iU, iV);
}

    
/**************************************************************
* Operators                                                   *
***************************************************************/


/**************************************************************
* Other helpful functions                                     *
***************************************************************/
cVoid Torus::Update(cFloat fIRadius, cFloat fERadius, cInt iU, cInt iV) {
	if (fIRadius <= TORUS_MIN_INT_RADIUS
		|| fERadius <= TORUS_MIN_EXT_RADIUS
		|| iU <= TORUS_MIN_U
		|| iV <= TORUS_MIN_V) {
			return;
	}
	mIntRadius = fIRadius;
	mExtRadius = fERadius;
	mU = iU;
	mV = iV;
	Object3D::Update(mV * mU, (mV * mU) << 1);
	cFloat du = TWOPI / iU;
	cFloat dv = TWOPI / iV;
	cFloat u = 0.0f, v;
	cInt i = 0;

	for (cInt uCnt = 0; uCnt < iU; uCnt++)	{
		v = 0.0f;
		for (cInt vCnt = 0; vCnt < iV; vCnt++)	{
			mVertexTable[i++] = Point4D((mExtRadius + mIntRadius * cosf(v)) * cosf(u), 
				(mExtRadius + mIntRadius * cosf(v)) * sinf(u), mIntRadius * sinf(v));
			v += dv;
		}
		u += du;
	}
	i = 0;
	for (cInt uCnt = 0; uCnt < iU; uCnt++) {
		for (cInt vCnt = 0; vCnt < iV; vCnt++)	{
			mEdgeTable[i].mBegin = iV * uCnt + vCnt;
			if (vCnt < iV - 1) {
				mEdgeTable[i].mEnd = iV * uCnt + vCnt + 1;
			} else {
				mEdgeTable[i].mEnd = iV * uCnt;
			}
			i++;

			mEdgeTable[i].mBegin = iV * uCnt + vCnt;
			if (uCnt < iU - 1) {
				mEdgeTable[i].mEnd = iV * (uCnt + 1) + vCnt;
			} else {
				mEdgeTable[i].mEnd = vCnt;
			}
			i++;
		}
	}
	for (i = 0; i < mNrOfVertices; i++) {
		mVertexTable[i] = mObjectMatrix * mVertexTable[i];
	}
}

cFloat Torus::GetInternalRadius() {
	return mIntRadius;
}

cFloat Torus::GetExternalRadius() {
	return mExtRadius;
}

cInt Torus::GetU() {
	return mU;
}

cInt Torus::GetV() {
	return mV;
}

/*virtual*/ cChar* Torus::GetName() {
	return "Torus";
}

/*virtual*/cVoid Torus::DisplayInfo(Renderer& renderer) {
	cChar pcBuff [MAX_BUF_SIZE];
	cInt iLineNr = 0;
	cInt iWidth = renderer.GetWidth(), iHeight = renderer.GetHeight();

	sprintf_s(pcBuff, "Tours Info:");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, mColor);
	sprintf_s(pcBuff, "R : %5.1f", mExtRadius);
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "r  : %5.1f", mIntRadius);
	renderer.DrawString( H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "U : %2.i", mU);
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "V : %2.i", mV);
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	iLineNr++;
	sprintf_s(pcBuff, "[Ctrl/Alt + R] - Increase/Decrease R");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "[Ctrl/Alt + T] - Increase/Decrease r");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "[T/G] - Increase/Decrease U");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
	sprintf_s(pcBuff, "[R/F] - Increase/Decrease V");
	renderer.DrawString(H_TXT_SPACER, iLineNr++ * V_TXT_SPACER, pcBuff, 
		false, true, true, Color::ToWinColor(WHITE));
}